#-*- coding: utf-8 -*-
"""不支持多线程, 大量使用了全局变量, 时间单位是秒
假定设备处于可信任的网络中，至少我们能保证客户端不会存在作弊的可能，可以减少数据验证的多个问题
"""

from project.application import app
from flask import Blueprint, render_template, jsonify
from flask import session, redirect, url_for, request, g
from functools import update_wrapper
import json
import time, datetime
import sys, os
import copy
import md5
import uuid
import base64

SYNC_SSID_CONFIG = app.config["SYNC_SSID_CONFIG"]
SYNC_FILE_NAME = app.config["SYNC_FILE_NAME"]
SYNC_TIME_FACTOR = app.config["SYNC_TIME_FACTOR"]

def read_sync_conf(conf_name):
    global  cids, next_ssid, wait_queue
    f = open(conf_name)
    start_zhushi = False
    json_string = ""
    for line in f.readlines():
        if len(line.strip()) == 0:
            continue
        if line.strip().startswith("#"):
            continue
        json_string += line 
    try:
        cids  = json.loads(json_string)  
        wait_queue = copy.deepcopy(cids)
        next_ssid = 0
    except:
        print u"json 文件错误"
        sys.exit(1)
    
if not app.config["SYNC_INITED"]:
    cids = None
    wait_queue = {}
    next_ssid = None
    read_sync_conf(SYNC_SSID_CONFIG)
    app.config["SYNC_INITED"] = True

def get_delay_from_dir(dir_name):
    pass

def get_delay_from_file(file_name):
    f = open(file_name)
    f.seek(0, 0)
    f.seek(0, 2)
    file_len = f.tell()
    file_syncTime = (file_len/1024.0/1024.0)*SYNC_TIME_FACTOR
    return file_syncTime

syncBp = Blueprint("sync", __name__, url_prefix="/sync")

file_syncTime = get_delay_from_file(SYNC_FILE_NAME)
min_begin_time = 0

def wait_toCids(cid, ssid):
    global wait_queue, cids 
    for index, client in enumerate(wait_queue[ssid]["clients"]):
        if client["cid"] != cid:
            continue
        client["status"] = "ok"
        client["delay_time"] = 0.0
        cids[ssid]["clients"].append(client) 
        wait_queue[ssid]["clients"].pop(index)
        return client
    return None
    
def get_macFromIP(ipString): 
    arp_rfd = os.popen("arp " + ipString)
    lines = list(arp_rfd.readlines())
    if len(lines) < 2:
        return None
    inet_mac = lines[1].split()[2] 
    return inet_mac.replace(":", "")

@syncBp.route("", methods=["GET", "POST"])
def sync_link():
    """1, 第一次请求什么参数也没有
       2，如需要第二次请求带第一次返回json的cid和ssid
    """
    global min_begin_time, cids, wait_queue, next_ssid
    if request.args.get("cid", None):
        """尝试从等待状态开始向工作状态
            如果工作状态满了则
        """
        cid = request.args.get("cid")
        ssid = request.args.get("ssid")
        # debug  此处的代码是设备从等待到工作的
        #end debug
        
        if len(cids[ssid]["clients"]) < cids[ssid]["count"]:  # 工作队列有空闲
            client = wait_toCids(cid, ssid) # 从等待到工作
            if client is None:
                print "do not have cid & ssid"
                return jsonify({"status": "error", "reason": "do not have  cid & ssid"})
            return jsonify(client)
        else:
            for index, client in enumerate(wait_queue[ssid]["clients"]):
                if client["cid"] != cid:
                    continue
                client["delay_time"] = file_syncTime + 60 
                return jsonify(client) 
    else:
        if app.config["NGINX"]: 
            client_ip = request.headers.get("x-forwarded-for") # 需要nginx的配置
        else:
            client_ip = request.remote_addr
        
        inet_mac = get_macFromIP(client_ip)
        if inet_mac is None:
            print "dont have mac address"
            return jsonify({"status": "error", "reason":"dont get ip: %s mac address"%(client_ip,)})
         
        ######################################################################### 
        #m = md5.md5(inet_mac)
        #cid = m.hexdigest()
        # debug
        cid = inet_mac
        # 多次请求debug, 时间运行逻辑保证不运行到此处
        for ssid, ssid_infos in cids.items():
            ssid_clients = ssid_infos.setdefault("clients", []) 
            for ssid_client in ssid_clients:
                if ssid_client["cid"] == cid:
                    return jsonify({"status": "error", "reason": "why ok"}) 
        for ssid, ssid_infos in wait_queue.items():
            ssid_clients = ssid_infos.setdefault("clients", []) 
            for ssid_client in ssid_clients:
                if ssid_client["cid"] == cid:
                    return jsonify({"status": "error", "reason": "why waiting"})
 
    begin_time = time.time()
    for ssid, ssid_infos in cids.items():
        ssid_clients = ssid_infos.setdefault("clients", []) 
        if len(ssid_clients) >= ssid_infos["count"]:
            continue
        
        ret =  {"status": "ok", "cid": cid, "ssid": ssid, "begin_time": begin_time, "delay_time": 0}
        ssid_clients.append(ret)
        if min_begin_time < begin_time:
            min_begin_time = begin_time
        return jsonify(ret)
    
   ###################运行到此处则进入等待队列#################
    ssids = sorted(wait_queue)
    cur_ssid = next_ssid%len(ssids)
    next_ssid = next_ssid + 1
    ssid = ssids[cur_ssid]
    ssid_clients = wait_queue[ssid].setdefault("clients", [])
    ssid_pos = len(ssid_clients)%wait_queue[ssid]["count"]

    fade_time =  begin_time - cids[ssid]["clients"][ssid_pos]["begin_time"]
    fade_time = fade_time > file_syncTime and file_syncTime or fade_time

    delay_time = (len(ssid_clients)/wait_queue[ssid]["count"] + 1)*file_syncTime - \
                     (fade_time)
    delay_time = delay_time < 10 and 10 or delay_time
    
    a = {"status": "waiting", "cid": cid, "ssid": ssid, "begin_time": begin_time, "delay_time": delay_time}
    ssid_clients.append({"status": "wait", "cid": cid, "ssid": ssid, "begin_time": begin_time, "delay_time": delay_time})
    return jsonify(a)

@syncBp.route("/end", methods=["GET", "POST"])
def sync_end():
    global min_begin_time, cids
    client_ip = request.headers.get("x-forwarded-for") # 需要nginx的配置
    cid = request.args.get("cid") 
    ssid = request.args.get("ssid") 

    for client in cids[ssid]["clients"]:
        if client["cid"] == cid:
            cids[ssid]["clients"].remove(client)
            return jsonify({"status":"ok"})

@syncBp.route("/version", methods=["GET", "POST"])
def sync_version():
    return jsonify({"version": app.config["SYNC_VERSION"]})

@syncBp.route("/newversion", methods=["GET", "POST"])
def sync_newversion():
    if request.method == "GET":
        return render_template("newversion")

    file = request.file
    upload_file = request.files["file"]
    file_name = upload_file.filename
    file_dir = "/srv/www/upversion"
    file_ext = os.path.splitext(upload_file.filename)[-1]
    upload_file.save(os.path.join(file_dir, file_name + file_ext))
    return jsonify({"status": "ok"})

@syncBp.route("/setting", methods=["GET", "POST"])
def sync_setting():
    if request.method == 'GET':
        return render_template("sync/setting.html")
    
    version = request.form.get("version")
    if len(version.strip()) == 0:
        return jsonify({"status": "error", "reason":"version empty"})
    if len(version.split(".")) != 3:
        return jsonify({"status": "error", "reason": "version error"})
    
    app.config["SYNC_VERSION"] =  version
    return jsonify({"status": "ok"})

